﻿using System.Linq.Expressions;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Query;
using SBlogCore.Common.App;
using SBlogCore.Common.DatabaseAccessor.Entitys;

namespace SBlogCore.Common.DatabaseAccessor.Repositorys.EFCore
{
    public partial class Repository<TEntity> where TEntity : class, IBaseEntity
    {
        /// <summary>
        /// 修改
        /// </summary>
        /// <param name="entity"></param>
        public void Update(TEntity entity)
        {
            UpdateOne(entity);
        }

        /// <summary>
        /// 批量修改
        /// </summary>
        /// <param name="entityParams"></param>
        public void UpdateRange(params TEntity[] entityParams)
        {
            UpdateMore(entityParams);
        }

        /// <summary>
        /// 异步修改
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public Task UpdateAsync(TEntity entity)
        {
            UpdateOne(entity);
            return Task.CompletedTask;
        }
        /// <summary>
        /// 异步批量修改
        /// </summary>
        /// <param name="entityParams"></param>
        /// <returns></returns>
        public Task UpdateRangeAsync(params TEntity[] entityParams)
        {
            UpdateMore(entityParams);
            return Task.CompletedTask;
        }
        /// <summary>
        /// 修改立即保存
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public int UpdateNow(TEntity entity)
        {
            UpdateOne(entity);
            return SaveChanges();
        }
        /// <summary>
        /// 批量修改立即保存
        /// </summary>
        /// <param name="entityParams"></param>
        /// <returns></returns>
        public int UpdateRangeNow(params TEntity[] entityParams)
        {
            UpdateMore(entityParams);
            return SaveChanges();
        }
        /// <summary>
        /// 异步修改立即保存
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public Task<int> UpdateNowAsync(TEntity entity)
        {
            return Task.FromResult(UpdateNow(entity));
        }
        /// <summary>
        /// 异步批量修改立即保存
        /// </summary>
        /// <param name="entityParams"></param>
        /// <returns></returns>
        public Task<int> UpdateRangeNowAsync(params TEntity[] entityParams)
        {
            return Task.FromResult(UpdateRangeNow(entityParams));
        }

        /// <summary>
        /// 更新一条记录指定字段的值
        /// </summary>
        /// <param name="model">数据实体</param>
        /// <param name="updateColumns">指定字段</param>
        /// <returns></returns>
        public void Update(TEntity model, params string[]? updateColumns)
        {
            if (updateColumns is {Length: > 0})
            {
                //Attach:将实体对象附加到上下文中；执行后的状态为unChanged
                if (_dbContext.Entry(model).State == EntityState.Added ||
                    _dbContext.Entry(model).State == EntityState.Detached) Entities.Attach(model);
                foreach (var propertyName in updateColumns)
                {
                    _dbContext.Entry(model).Property(propertyName).IsModified = true;
                }
            }
            else
            {
                _dbContext.Entry(model).State = EntityState.Modified;
            }
        }
        /// <summary>
        /// 更新一条记录指定字段的值
        /// </summary>
        /// <param name="model"></param>
        /// <param name="names"></param>
        public void Update(TEntity model, IEnumerable<string> names)
        {
            Update(model, names.ToArray());
        }

        /// <summary>
        /// 按条件修改记录
        /// </summary>
        /// <param name="propertyPredicate"></param>
        public Task<int> UpdateAsync(Expression<Func<TEntity, TEntity>> propertyPredicate)
        {
          var updateContext = _dbContext.BatchUpdate<TEntity>();

          return updateContext.ExecuteAsync();
        }

        private void UpdateMore(TEntity[] entityParams)
        {
            foreach (var entity in entityParams)
            {
                UpdateEntityWork(entity);
            }
            Entities.UpdateRange(entityParams);
        }

        /// <summary>
        /// 按条件批量修改
        /// </summary>
        /// <param name="setPropertyCalls"></param>
        /// <returns></returns>
        public int ExecuteUpdate(Expression<Func<SetPropertyCalls<TEntity>, SetPropertyCalls<TEntity>>> setPropertyCalls)
        {
           return Entities.ExecuteUpdate(setPropertyCalls);
        }
        /// <summary>
        /// 按条件批量异步修改
        /// </summary>
        /// <param name="setPropertyCalls"></param>
        /// <returns></returns>
        public  Task<int> ExecuteUpdateAsync(Expression<Func<SetPropertyCalls<TEntity>, SetPropertyCalls<TEntity>>> setPropertyCalls)
        {
            return Entities.ExecuteUpdateAsync(setPropertyCalls);
        }

        private void UpdateOne(TEntity entity)
        {
            Entities.Update(UpdateEntityWork(entity)!);
        }
        private static TEntity? UpdateEntityWork(TEntity entity)
        {
            if (entity is not CreateEntity createEntity) return entity;
            createEntity.UpdatedTime ??= DateTime.Now;
            var userToken = AppBase.GetJwtUser();
            if (userToken!=null)
            {
                createEntity.UpdatedUserId ??= userToken.Uid;
            }
            return createEntity as TEntity;
        }
    }
}
